(*
   Copyright (c) 2023-2025 Semgrep Inc.

   This library is free software; you can redistribute it and/or
   modify it under the terms of the GNU Lesser General Public License
   version 2.1 as published by the Free Software Foundation.

   This library is distributed in the hope that it will be useful, but
   WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file
   LICENSE for more details.
*)
(*
   Wrapper around the aliengrep matcher (a generic mode variant)
*)

let convert_pos ~file (loc : Aliengrep.Match.loc) =
  (* single "token" spanning the whole match *)
  let bytepos = loc.start in
  let line, column = Xpattern_matcher.line_col_of_charpos file bytepos in
  let pos = Pos.make file ~line ~column bytepos in
  { Loc.str = loc.substring; pos }

let convert_loc ~file (loc : Aliengrep.Match.loc) =
  (* single "token" spanning the whole match *)
  let start_pos = convert_pos ~file loc in
  (* a location is a pair of positions/tokens so we create an empty token
     at the end of the match *)
  let end_pos =
    let bytepos = loc.start + loc.length in
    let line, column = Xpattern_matcher.line_col_of_charpos file bytepos in
    let pos = Pos.make file ~line ~column bytepos in
    { Loc.str = ""; pos }
  in
  (start_pos, end_pos)

let convert_capture ~file
    ((mv : Aliengrep.Pat_compile.metavariable), (loc : Aliengrep.Match.loc)) =
  let str = loc.substring in
  let pos = convert_pos ~file loc in
  let tok = Tok.tok_of_loc pos in
  let name_with_dollar = Aliengrep.Pat_compile.string_of_metavariable mv in
  (name_with_dollar, Xpattern_matcher.mval_of_string str tok)

(* Convert locations to the file/line/column format etc. *)
let convert_match ~file (match_ : Aliengrep.Match.match_) =
  let loc = convert_loc ~file match_.match_loc in
  let env = List_.map (convert_capture ~file) match_.captures in
  (loc, env)

let aliengrep_matcher target_str file pat =
  Aliengrep.Match.search pat target_str |> List_.map (convert_match ~file)

let matches_of_aliengrep patterns lazy_contents (file : Fpath.t) origin =
  let init _ =
    (* TODO: ignore binary files like spacegrep? *)
    (* TODO: preprocess and remove comments like spacegrep does *)
    let content, time = Common.force_lazy_with_time lazy_contents in
    (Some content, time)
  in
  Xpattern_matcher.matches_of_matcher patterns
    { init; matcher = aliengrep_matcher }
    file origin
